home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 April / EnigmA AMIGA RUN 17 (1997)(G.R. Edizioni)(IT)[!][issue 1997-04][EAR-CD].iso / EARCD / comm / term / Sterm.lha / sterm / sterm.c < prev    next >
C/C++ Source or Header  |  1996-12-20  |  19KB  |  587 lines

  1. /* STerm 1.0 -- © 1995 Dominique Lorre
  2.  *
  3.  * This was planned to be a very small terminal program (Small Term)
  4.  * that I developped because a lack of place on my A600 disk
  5.  * but it happened that I had to make it work with SAD (SAD Term).
  6.  * Other possibilities are SerialTerm 8->, SmartTerm ;-),...
  7.  *
  8.  * This software is in the Public Domain. You can modify it but in
  9.  * this case you should find a new name for the program.
  10.  */
  11.  
  12. #include <exec/types.h>
  13. #include <devices/console.h>
  14. #include <devices/serial.h>
  15. #include <string.h>
  16.  
  17. #include <proto/exec.h>
  18. #include <proto/dos.h>
  19. #include <proto/intuition.h>
  20. #include <clib/alib_protos.h>
  21.  
  22. static struct MsgPort *SerialPort, *conport ;
  23. static struct IOExtSer *ReadIO, *WriteIO ;
  24. static LONG Error ;
  25. static ULONG SerSig ;
  26. static ULONG ConSig ;
  27. static ULONG WinSig ;
  28. static ULONG signal ;
  29. static struct FileHandle *fh ;
  30. static UBYTE SerBuf[512] ;
  31. static UBYTE ConBuf[512] ;
  32. static BOOL fin=FALSE ;
  33. static BPTR msgout ;
  34. static struct Window *win ;
  35. static struct IOStdReq *conreq, *outreq ;
  36. static struct IntuiMessage *imsg ;
  37.  
  38. /* Command Datas are here */
  39. static LONG hlen = 0, alen = 0 ;
  40. static BOOL RawMode = TRUE ;
  41. static LONG HexMode = 0 ;
  42.  
  43. /* SAD Datas are here */
  44.  
  45. static LONG length = 0 ;
  46. static BOOL SADAsk = FALSE ;
  47. static BOOL SADV39 = FALSE ;
  48.  
  49. static UBYTE ResetCmd[6] = { 0xAF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF } ;
  50. static UBYTE AbortCmd[6] = { 0xAF, 0x08, 0x00, 0x00, 0x00, 0x00 } ;
  51. static UBYTE ReadWordCmd[6] = { 0xAF, 0x05, 0x00, 0xF8, 0x00, 0x00 } ;
  52. static LONG rate[8] = {
  53.     110, 300, 1200, 2400, 4800, 9600, 19200, 31250
  54. };
  55. static UBYTE srate[8][6] = {
  56.     "110", "300", "1200", "2400", "4800", "9600", "19200", "31250"
  57. };
  58.  
  59. /* Functions Prototypes */
  60.  
  61. BOOL InitDevs(void) ;
  62. BOOL CloseDevs(WORD) ;
  63. BOOL InitConsole(void) ;
  64. BOOL CloseConsole(WORD) ;
  65.  
  66. BOOL SADCheckVersion(void) ;
  67. void SADAbort(void) ;
  68. void SADReset(void) ;
  69. void SADSendCmd(STRPTR cmd, LONG len) ;
  70. BOOL SADAckCmd(UBYTE ack) ;
  71. void ConOut(STRPTR msg) ;
  72.  
  73. void SetBaudRate(long Baud) ;
  74. void DisplayHelp(void) ;
  75. void SendCom(STRPTR s) ;
  76.  
  77.  
  78. void main(void)
  79. {
  80. struct IOExtSer *srep ;
  81. struct IOStdReq *crep ;
  82.  
  83.     if (InitDevs()) {
  84.         if (InitConsole()) {
  85.             do {
  86.                 signal = Wait(SerSig|ConSig|WinSig) ;
  87.                 /* No class check because only IDCMP_CLOSEWINDOW here */
  88.                 if (signal & WinSig) {
  89.                     while (imsg = (struct IntuiMessage *)GetMsg(win->UserPort)) {
  90.                         ReplyMsg((struct Message *)imsg) ;
  91.                         fin = TRUE ;
  92.                     }
  93.                 }
  94.                 /* serial stuff */
  95.                 if (signal & SerSig) {
  96.                     while (srep = (struct IOExtSer *)GetMsg(SerialPort)) {
  97.                         /* Here we check for SAD[?|!|¿] commands */
  98.                         if (!srep->IOSer.io_Error && !SADAsk) {
  99.                             if (length == 3) {
  100.                                 if (SerBuf[0] == '!' || SerBuf[0] == '?' ||
  101.                                         SerBuf[0] == 0xBF) {
  102.                                     SADAsk = TRUE ;
  103.                                     length = 0 ;
  104.                                 }
  105.                                 else
  106.                                     length = 0 ;
  107.                             }
  108.                             if (!RawMode) {
  109.                                 if (length == 2)
  110.                                     length = (SerBuf[0] == 'D')?3:0 ;
  111.                                 if (length == 1)
  112.                                     length = (SerBuf[0] == 'A')?2:0 ;
  113.                                 if (length == 0)
  114.                                     length = (SerBuf[0] == 'S')?1:0 ;
  115.  
  116.                                 if (hlen == 2) {
  117.                                     if ((SerBuf[0] | 0x20) == 'x') {
  118.                                         HexMode = 1 ;
  119.                                         ConOut("HexMode set.\n") ;
  120.                                     }
  121.                                     hlen = 0 ;
  122.                                 }
  123.                                 if (hlen == 1)
  124.                                     hlen = ((SerBuf[0] | 0x20) == 'e')?2:0;
  125.                                 if (hlen == 0)
  126.                                     hlen = ((SerBuf[0] | 0x20) == 'h')?1:0;
  127.  
  128.                                 if (alen == 2) {
  129.                                     if ((SerBuf[0] | 0x20) == 'c') {
  130.                                         HexMode = 0 ;
  131.                                         ConOut("HexMode unset.\n") ;
  132.                                     }
  133.                                     alen = 0 ;
  134.                                 }
  135.                                 if (alen == 1)
  136.                                     alen = ((SerBuf[0] | 0x20) == 's')?2:0;
  137.                                 if (alen == 0)
  138.                                     alen = ((SerBuf[0] | 0x20) == 'a')?1:0;
  139.  
  140.                                 if (alen == 2) {
  141.                                     if ((SerBuf[0] | 0x20) == 'h') {
  142.                                         HexMode = 2 ;
  143.                                         ConOut("Semi HexMode set.\n") ;
  144.                                     }
  145.                                     alen = 0 ;
  146.                                 }
  147.                                 if (alen == 1)
  148.                                     alen = ((SerBuf[0] | 0x20) == 'e')?2:0;
  149.                                 if (alen == 0)
  150.                                     alen = ((SerBuf[0] | 0x20) == 's')?1:0;
  151.                             }
  152.                             SendCom(SerBuf) ;
  153.                             if (SADAsk) {
  154.                                 ConOut(" command received.\nPlease quit STerm and launch Wack TARGET 0 command.\nPress 'R' key to reset computer.\nPress any other key to abort\n") ;
  155.                             }
  156.                         }
  157.                         ReadIO->IOSer.io_Command = CMD_READ;
  158.                         ReadIO->IOSer.io_Data = (APTR)SerBuf;
  159.                         ReadIO->IOSer.io_Length = 1;
  160.                         SendIO((struct IORequest *)ReadIO);
  161.                     }
  162.                 }
  163.                 /* Console stuff */
  164.                 if (signal & ConSig) {
  165.                     while (crep = (struct IOStdReq *)GetMsg(conport)) {
  166.                         ConBuf[crep->io_Actual] = '\0' ;
  167.                         if (!crep->io_Error) {
  168.                             if (SADAsk) {
  169.                                 SADAsk = FALSE ;
  170.                                 if (!CheckIO((struct IORequest *)ReadIO))
  171.                                     AbortIO((struct IORequest *)ReadIO) ;
  172.                                 WaitIO((struct IORequest *)ReadIO) ;
  173.  
  174.                                 /* ['r', 'R']  means Reset */
  175.                                 if ((ConBuf[0] | 0x20) == 'r')
  176.                                     SADReset() ;
  177.                                 else
  178.                                     SADAbort() ;
  179.  
  180.                                 ReadIO->IOSer.io_Command = CMD_READ;
  181.                                 ReadIO->IOSer.io_Data = (APTR)SerBuf;
  182.                                 ReadIO->IOSer.io_Length = 1;
  183.                                 SendIO((struct IORequest *)ReadIO);
  184.                             }
  185.                             if (ConBuf[0] == 0x9B) { /* CSI: do special work */
  186.                                 if (ConBuf[2] == '~') {
  187.                                     if (ConBuf[1] == 0x3F)
  188.                                         DisplayHelp() ;
  189.                                     else if (ConBuf[1] >= 0x30 &&
  190.                                             ConBuf[1] <= 0x37) {
  191.                                         SetBaudRate(ConBuf[1]-0x30) ;
  192.                                     }
  193.                                     else if (ConBuf[1] == 0x38) {
  194.                                         if (HexMode == 2) {
  195.                                             ConOut("HexMode unset.\n") ;
  196.                                             HexMode = 0 ;
  197.                                         }
  198.                                         else if (HexMode == 0) {
  199.                                             ConOut("HexMode set.\n") ;
  200.                                             HexMode = 1 ;
  201.                                         }
  202.                                         else {
  203.                                             ConOut("Semi-HexMode set.\n") ;
  204.                                             HexMode = 2 ;
  205.                                         }
  206.                                     }
  207.                                     else if (ConBuf[1] == 0x39) {
  208.                                         if (RawMode) {
  209.                                             ConOut("RawMode unset.\n") ;
  210.                                             RawMode = FALSE ;
  211.                                         }
  212.                                         else {
  213.                                             ConOut("RawMode set.\n") ;
  214.                                             RawMode = TRUE ;
  215.                                         }
  216.                                     }
  217.                                 }
  218.                             }
  219.                             ConBuf[crep->io_Actual] = '\0' ;
  220.                             WriteIO->IOSer.io_Command = CMD_WRITE;
  221.                             WriteIO->IOSer.io_Data = (APTR)ConBuf;
  222.                             WriteIO->IOSer.io_Length = strlen(ConBuf);
  223.                             DoIO((struct IORequest *)WriteIO);
  224.  
  225.                             Write(msgout, ConBuf, strlen(ConBuf)) ;
  226.  
  227.                             conreq->io_Command = CMD_READ;
  228.                             conreq->io_Data = (APTR)ConBuf;
  229.                             conreq->io_Length = 512;
  230.                             SendIO((struct IORequest *)conreq);
  231.                         }
  232.                     }
  233.                 }
  234.             } while (!fin) ;
  235.             CloseConsole(0) ;
  236.         }
  237.         CloseDevs(0) ;
  238.     }
  239. }
  240.  
  241.  
  242. /*
  243.  * InitDevs
  244.  * Alloc serial resources
  245.  * return TRUE for success
  246.  */
  247. BOOL InitDevs(VOID)
  248. {
  249.  
  250.     if (SerialPort = (struct MsgPort *)CreateMsgPort()) {
  251.         SerSig = (1L << SerialPort->mp_SigBit);
  252.     }
  253.     else
  254.         return CloseDevs(1);
  255.     if ((ReadIO = (struct IOExtSer *)
  256.             CreateIORequest((struct MsgPort *)SerialPort, sizeof(struct IOExtSer))) == NULL)
  257.         return CloseDevs(2);
  258.  
  259.     ReadIO->io_SerFlags = SERF_SHARED;
  260.     if (Error = OpenDevice(SERIALNAME, 0, (struct IORequest *)ReadIO, 0))
  261.         return CloseDevs(3);
  262.  
  263.     if ((WriteIO = (struct IOExtSer *)
  264.             CreateIORequest((struct MsgPort *)SerialPort, sizeof(struct IOExtSer))) == NULL)
  265.         return CloseDevs(4);
  266.     CopyMem(ReadIO, WriteIO, sizeof(struct IOExtSer)) ;
  267.  
  268.     ReadIO->IOSer.io_Command = CMD_READ; /* Start reading serial */
  269.     ReadIO->IOSer.io_Data = (APTR)SerBuf;
  270.     ReadIO->IOSer.io_Length = 1;
  271.     SendIO((struct IORequest *)ReadIO);
  272.  
  273.     return TRUE;
  274. }
  275.  
  276.  
  277. /*
  278.  * CloseDevs
  279.  * Frees serial resources
  280.  * return TRUE if called with level = 0 (no problem)
  281.  */
  282. BOOL CloseDevs(WORD level)
  283. {
  284.     if (level)
  285.         Printf("devs:%ld\n", level);
  286.     switch (level) {
  287.         case 0:
  288.             DeleteIORequest((struct IORequest *)WriteIO) ;
  289.         case 4:
  290.             CloseDevice((struct IORequest *)ReadIO);
  291.         case 3:
  292.             DeleteIORequest((struct IORequest *)ReadIO);
  293.         case 2:
  294.             DeleteMsgPort(SerialPort);
  295.         case 1:
  296.             return (BOOL)(level?FALSE:TRUE);
  297.     }
  298. }
  299.  
  300. /*
  301.  * InitConsole
  302.  * Alloc console structures
  303.  * return TRUE for success
  304.  */
  305. BOOL InitConsole(VOID)
  306. {
  307. STRPTR msgtitle = "CON:20/170/600/30/Echo Console" ;
  308.  
  309.     msgout = Open(msgtitle, MODE_OLDFILE) ;
  310.     if (!msgout)
  311.         return CloseConsole(1) ;
  312.  
  313.     win = OpenWindowTags(NULL,
  314.     WA_Left, 20,
  315.     WA_Top, 20,
  316.     WA_Width, 600,
  317.     WA_Height, 140,
  318.     WA_MaxWidth, 640,
  319.     WA_MaxHeight, 200,
  320.     WA_Title, "STerm V1.0 ©1994, Dominique Lorre -- Help key helps.",
  321.     WA_CloseGadget, TRUE,
  322.     WA_SizeGadget, TRUE,
  323.     WA_DepthGadget, TRUE,
  324.     WA_DragBar, TRUE,
  325.     WA_Activate, TRUE,
  326.     WA_SimpleRefresh, TRUE,
  327.     WA_IDCMP, IDCMP_CLOSEWINDOW,
  328.     TAG_DONE) ;
  329.     if (!win)
  330.         return CloseConsole(2) ;
  331.  
  332.     WinSig = 1 << win->UserPort->mp_SigBit ;
  333.  
  334.     conport = CreateMsgPort() ;
  335.     if (!conport)
  336.         return CloseConsole(3) ;
  337.  
  338.     ConSig = 1 << conport->mp_SigBit ;
  339.  
  340.     conreq = CreateStdIO(conport) ;
  341.     if (!conreq)
  342.         return CloseConsole(4) ;
  343.  
  344.     outreq = CreateStdIO(conport) ;
  345.     if (!outreq)
  346.         return CloseConsole(5) ;
  347.  
  348.     conreq->io_Data = win ;
  349.     Error = OpenDevice("console.device", 3, (struct IORequest *)conreq, 0) ;
  350.     if (Error)
  351.         return CloseConsole(6) ;
  352.     *outreq = *conreq ;
  353.  
  354.     conreq->io_Command = CMD_READ; /* Starts reading console */
  355.     conreq->io_Data = (APTR)ConBuf;
  356.     conreq->io_Length = 512;
  357.     SendIO((struct IORequest *)conreq);
  358.     return TRUE ;
  359. }
  360.  
  361. /*
  362.  * CloseConsole
  363.  * Frees console structures
  364.  * return TRUE if called with level = 0 (no problem)
  365.  */
  366. BOOL CloseConsole(WORD level)
  367. {
  368.     if (level)
  369.         Printf("console : %ld\n", level) ;
  370.     switch (level) {
  371.     case 0:
  372.         CloseDevice((struct IORequest *)conreq) ;
  373.     case 6:
  374.         DeleteStdIO(outreq) ;
  375.     case 5:
  376.         DeleteStdIO(conreq) ;
  377.     case 4:
  378.         DeleteMsgPort(conport) ;
  379.     case 3:
  380.         CloseWindow(win) ;
  381.     case 2:
  382.         Close(msgout) ;
  383.     case 1:
  384.         return (BOOL)(level?FALSE:TRUE) ;
  385.     }
  386. }
  387.  
  388. /*
  389.  * SADCheckVersion
  390.  * Checks if SAD is running on V39 or V40+
  391.  * return TRUE for success
  392.  */
  393. BOOL SADCheckVersion(void)
  394. {
  395. BOOL acked = FALSE ;
  396. long i, length ;
  397.  
  398.     SADSendCmd(ReadWordCmd, 6) ;
  399.     ReadIO->IOSer.io_Command = SDCMD_QUERY ;
  400.     DoIO((struct IORequest *)ReadIO) ;
  401.     length = ReadIO->IOSer.io_Actual ;
  402.  
  403.     if (!ReadIO->IOSer.io_Error) {
  404.         ReadIO->IOSer.io_Command = CMD_READ;
  405.         ReadIO->IOSer.io_Data = (APTR)SerBuf;
  406.         ReadIO->IOSer.io_Length = length;
  407.         DoIO((struct IORequest *)ReadIO);
  408.     }
  409.  
  410.     /* This is a "defensive programming" loop. SAD seems to clear the
  411.        serial buffers before replying.
  412.      */
  413.     if (!ReadIO->IOSer.io_Error) {
  414.         for (i=0; i<length-1 && !acked ; i++) {
  415.             acked = SerBuf[i] == 0x00 &&
  416.                 (SerBuf[i+1] == 0x05 || SerBuf[i+1] == 0x06) ;
  417.         }
  418.     }
  419.     if (acked) {
  420.         SADV39 = (SerBuf[i] == 0x06) ;
  421.     }
  422.     else
  423.         ConOut("Unable to contact SAD: SAD Link lost\n") ;
  424.     return acked ;
  425. }
  426.  
  427. /*
  428.  * SADReset
  429.  * Send Reset Cmd to SAD
  430.  */
  431. void SADReset(void)
  432. {
  433. UBYTE cn ;
  434.  
  435.     if (SADCheckVersion()) {
  436.         cn = SADV39?0x0F:0x10 ;
  437.         ResetCmd[1] = cn ;
  438.         SADSendCmd(ResetCmd, 6) ; /* Unable to check ack here */
  439.         ConOut("Target Computer should be rebooting now ...\n") ;
  440.     }
  441. }
  442.  
  443. /*
  444.  * SADAbort
  445.  * Sends Abort Cmd to SAD
  446.  */
  447. void SADAbort(void)
  448. {
  449. UBYTE cn ;
  450.  
  451.     if (SADCheckVersion()) {
  452.         cn = SADV39?0x07:0x08 ;
  453.         AbortCmd[1] = cn ;
  454.         SADSendCmd(AbortCmd, 6) ;
  455.         if (!SADAckCmd(0x08))
  456.             ConOut("Unable to Abort: SAD Link lost\n") ;
  457.         else
  458.             ConOut("Target Computer now has regained control...\n") ;
  459.     }
  460. }
  461.  
  462. /*
  463.  * SADSendCmd
  464.  * Sends command to serial with a little delay to allow ack checking
  465.  */
  466. void SADSendCmd(STRPTR cmd, LONG len)
  467. {
  468.     WriteIO->IOSer.io_Command = CMD_WRITE ;
  469.     WriteIO->IOSer.io_Data = (APTR)cmd;
  470.     WriteIO->IOSer.io_Length = len ;
  471.     DoIO((struct IORequest *)WriteIO) ;
  472.     Delay(10) ;                         /* Give time to Time */
  473. }
  474.  
  475. /*
  476.  * SADAckCmd
  477.  * Checks if command identified by ack has succeeded
  478.  * returns TRUE for success
  479.  */
  480. BOOL SADAckCmd(UBYTE ack)
  481. {
  482. BOOL acked = FALSE ;
  483. long i, length ;
  484.  
  485.     ReadIO->IOSer.io_Command = SDCMD_QUERY ; /* How many bytes in serial ? */
  486.     DoIO((struct IORequest *)ReadIO) ;
  487.     length = ReadIO->IOSer.io_Actual ;
  488.     if (!ReadIO->IOSer.io_Error) {
  489.         ReadIO->IOSer.io_Command = CMD_READ; /* Read them */
  490.         ReadIO->IOSer.io_Data = (APTR)SerBuf;
  491.         ReadIO->IOSer.io_Length = length;
  492.         DoIO((struct IORequest *)ReadIO);
  493.  
  494.     }
  495.     if (!ReadIO->IOSer.io_Error) {
  496.         /* This is a "defensive programming" loop. SAD seems to clear the
  497.            serial buffers before replying.
  498.          */
  499.         for (i=0; i<length-1 && !acked ; i++) { /* Check if ack is inside */
  500.             acked = SerBuf[i] == 0x00 && (SerBuf[i+1] == ack) ;
  501.         }
  502.     }
  503.     return acked ;
  504. }
  505.  
  506. /*
  507.  * ConOut
  508.  * Sends msg to Serial Console
  509.  */
  510. void ConOut(STRPTR msg)
  511. {
  512. static UBYTE selon[5] = {0x9B, ';', '3', '3', 'm' };
  513. static UBYTE seloff[5] = {0x9B, ';', '3', '1', 'm' };
  514.     outreq->io_Command = CMD_WRITE;
  515.     outreq->io_Data = selon ;
  516.     outreq->io_Length = 5 ;
  517.     DoIO((struct IORequest *)outreq);
  518.     outreq->io_Data = msg ;
  519.     outreq->io_Length = strlen(msg) ;
  520.     DoIO((struct IORequest *)outreq);
  521.     outreq->io_Data = seloff;
  522.     outreq->io_Length = 5 ;
  523.     DoIO((struct IORequest *)outreq);
  524. }
  525.  
  526. void SetBaudRate(long Baud)
  527. {
  528.     WriteIO->IOSer.io_Command = CMD_RESET;
  529.     DoIO((struct IORequest *)WriteIO);
  530.     WriteIO->IOSer.io_Command = SDCMD_SETPARAMS;
  531.     WriteIO->io_SerFlags = SERF_RAD_BOOGIE | SERF_SHARED;
  532.     WriteIO->io_ExtFlags = 0;
  533.     WriteIO->io_Baud = rate[Baud];
  534.     WriteIO->io_RBufLen = 512;
  535.     WriteIO->io_ReadLen = 8;
  536.     WriteIO->io_WriteLen = 8;
  537.     WriteIO->io_StopBits = 1;
  538.     DoIO((struct IORequest *)WriteIO);
  539.     ConOut("Rate set to ") ;
  540.     ConOut(srate[Baud]) ;
  541.     ConOut(" bauds.\n") ;
  542. }
  543.  
  544. void DisplayHelp(void)
  545. {
  546.     ConOut("STerm V1.0, ©1995, Dominique Lorre\n") ;
  547.     ConOut("Click window close gadget to quit.\n") ;
  548.     ConOut("Serial rates :\n") ;
  549.     ConOut("\t F1:   110 bauds\n") ;
  550.     ConOut("\t F2:   300 bauds\n") ;
  551.     ConOut("\t F3:  1200 bauds\n") ;
  552.     ConOut("\t F4:  2400 bauds\n") ;
  553.     ConOut("\t F5:  4800 bauds\n") ;
  554.     ConOut("\t F6:  9600 bauds\n") ;
  555.     ConOut("\t F7: 19200 bauds\n") ;
  556.     ConOut("\t F8: 31250 bauds\n") ;
  557.     ConOut("\t F9: Toggle Hex Mode\n") ;
  558.     ConOut("\tF10: Toggle Raw Mode\n") ;
  559. }
  560.  
  561. void SendCom(STRPTR s)
  562. {
  563. static char hexa[3] = {'$', '0', '0'};
  564.  
  565.     outreq->io_Command = CMD_WRITE;
  566.     if (!HexMode || ((HexMode == 2) && s[0] >= 0x20 && s[0] < 0x7F)) {
  567.         outreq->io_Data = (APTR)s ;
  568.         outreq->io_Length = 1;
  569.         DoIO((struct IORequest *)outreq);
  570.     }
  571.     else {
  572.         hexa[1] = (s[0] & 0xF0) >> 4 ;
  573.         hexa[2] = s[0] & 0x0F ;
  574.         if (hexa[1] > 9)
  575.             hexa[1] += 'A' - 10 ;
  576.         else
  577.             hexa[1] += '0' ;
  578.         if (hexa[2] > 9)
  579.             hexa[2] += 'A' - 10 ;
  580.         else
  581.             hexa[2] += '0' ;
  582.         outreq->io_Data = (APTR)hexa ;
  583.         outreq->io_Length = 3 ;
  584.         DoIO((struct IORequest *)outreq);
  585.     }
  586. }
  587.